package ar.uba.fi.tecnicas.vista.consola;

import java.awt.Dimension;
import java.awt.Point;
import java.io.*;
import java.util.*;

import ar.uba.fi.tecnicas.fabrica.*;
import ar.uba.fi.tecnicas.fabrica.Terreno.ModoAdquisicion;
import ar.uba.fi.tecnicas.juego.Juego;

public class Main
{
	private static BufferedReader input = new BufferedReader(new InputStreamReader(System.in) );
	
	private static Main main = new Main();
	
	private static Menues menues = main.new Menues();
	private static Control control = main.new Control();

	private static Juego juego = Juego.instancia;
	
	public static void main(String args[])
	{
		System.out.println("Simulador Fabrica v0.2");
		
		juego.crearJugador(menues.getInputString("Ingrese el nombre del jugador: "));
		
		Main.imprimirConfiguracion();
		
		Main.mainLoop();
	}
	
	public static void mainLoop()
	{
		OpcionPrincipal opcion = OpcionPrincipal.Ninguna;

		while(opcion != OpcionPrincipal.Salir)
		{			
			opcion = menues.menuPrincipal();
			control.procesarOpcionPrincpal(opcion);
		}

		System.exit(0);
	}

	public static void setUpInicialParaPrueba()
	{		
		try
		{
			/// Comprar terreno
			juego.getJugador().adquirirTerreno(0, ModoAdquisicion.Compra);
			/// Crear Linea 1
			juego.getJugador().crearLineaProduccion("Linea 1");
			juego.getJugador().crearLineaProduccion("Linea 2");
			/// Comprar maquina 1
			juego.getJugador().comprarMaquina(
				1,
				new Point(10, 10),
				0
			);			
			/// Comprar maquina 2
			juego.getJugador().comprarMaquina(
				2,
				new Point(20, 10),
				0
			);
			
			juego.getJugador().conectarMaquinas(new Point(10, 10), new Point(20, 10));
		}
		catch (Exception e) 
		{
			 menues.mensaje(e.getMessage());
		}
	}
	
	public static void imprimirConfiguracion()
	{
		System.out.println("----------------------");
		System.out.println("Tipos de Materia Prima");
		System.out.println("----------------------");
		
		Collection<TipoMateriaPrima> tiposMateriaPrima =  juego.getTiposMateriaPrima();
		for (TipoMateriaPrima tipo : tiposMateriaPrima)
		{
			System.out.println(tipo.getNombre());
		}

		System.out.println("----------------");
		System.out.println("Tipos de Maquina");
		System.out.println("----------------");
		
		Collection<TipoMaquina> tiposMaquina =  juego.getTiposMaquina();
		for (TipoMaquina tipo : tiposMaquina)
		{
			System.out.println(tipo.getNombre());
		}
		
		System.out.println("----------------");
		System.out.println("Transformaciones");
		System.out.println("----------------");
		
		Collection<Transformacion> transformaciones = juego.getTransformaciones();
		for (Transformacion transformacion : transformaciones)
		{
			System.out.println(transformacion.getNombre());
		}
		
		System.out.println("----------------");
		System.out.println("Terrenos");
		System.out.println("----------------");
		
		Collection<Terreno> terrenos = juego.getTerrenos();
		for (Terreno terreno : terrenos)
		{
			System.out.println(terreno.getAncho() + " x " + terreno.getAlto());
		}
		
		System.out.println("-----------------");
		System.out.println("Tipos de Producto");
		System.out.println("-----------------");
		
		Collection<TipoProducto> tiposProducto = juego.getTiposProducto();
		for (TipoProducto tipoProducto : tiposProducto)
		{
			System.out.println(tipoProducto.getNombre());
			for(Transformacion transformacion : tipoProducto.getTransformaciones())
			{
				System.out.println("-- " + transformacion.getNombre());
			}
			for(MateriaPrima materia : tipoProducto.getMateriasPrimas())
			{
				System.out.println(".. " + materia.getTipo().getNombre());
			}

		}		
	}

	public enum OpcionPrincipal
	{
		Ninguna,
		AdquirirTerreno,
		CrearLinea,
		ComprarMaquina,
		ConectarMaquinas,
		CongelarTiempo,
		DescongelarTiempo,
		Salir
	}

	public class Menues
	{
		public String getInputString(String mensaje)
		{
			String dato = null;
			
			System.out.print(mensaje);
			
			try
			{
				dato = input.readLine();
			}
			catch (Exception e) {}
			
			return dato;
		}
		
		public int getInputInt(String mensaje)
		{			
			int opcion = -1;
			
			try
			{
				 opcion = Integer.valueOf(this.getInputString(mensaje));
			}
			catch (NumberFormatException e) 
			{
				System.out.println("Ingrese un numero.");
			}
			
			return opcion;
		}
		
		public int getInputInt(String mensaje, int min, int max)
		{			
			int opcion = -1;
			// Para segurar que ingresa algo
			boolean ingreso = false;
			
			do
			{
				try
				{
					 opcion = Integer.valueOf(this.getInputString(mensaje));
					 ingreso = true;
				}
				catch (NumberFormatException e) 
				{
					System.out.println("Ingrese un numero.");
				}
			}while(opcion < min || max < opcion || !ingreso);
			
			return opcion;
		}
		
		public void mensaje(String mensaje)
		{
			System.out.println(mensaje);
		}

		public OpcionPrincipal menuPrincipal()
		{
			List<String> opcionesString = new ArrayList<String>();
			opcionesString.add("Comprar Terreno");
			opcionesString.add("Crear Linea Nueva");
			opcionesString.add("Comprar Maquina");
			opcionesString.add("Conectar Maquina");
			opcionesString.add("Congelar Tiempo");
			opcionesString.add("Descongelar Tiempo");
			opcionesString.add("Salir");
			
			List<OpcionPrincipal> opcionesPrincial = new ArrayList<OpcionPrincipal>();
			opcionesPrincial.add(OpcionPrincipal.AdquirirTerreno);
			opcionesPrincial.add(OpcionPrincipal.CrearLinea);
			opcionesPrincial.add(OpcionPrincipal.ComprarMaquina);
			opcionesPrincial.add(OpcionPrincipal.ConectarMaquinas);
			opcionesPrincial.add(OpcionPrincipal.CongelarTiempo);
			opcionesPrincial.add(OpcionPrincipal.DescongelarTiempo);
			opcionesPrincial.add(OpcionPrincipal.Salir);

			this.mensaje("/*****************************/");
			this.mensaje("Jugador: " + juego.getJugador().getNombre() + " - Capital: " + String.valueOf(juego.getJugador().getCapital()));
			this.mensaje("Hora: " + juego.getHoraDelDia());
			this.mensaje("Seleccione un opcion:");
			
			int index = 1;
			for(String opcionStr : opcionesString)
			{
				this.mensaje(String.valueOf(index) + ". " + opcionStr);
				index++;
			}

			this.mensaje("/*****************************/");

			int opcionInt = this.getInputInt("Opcion: ", 1, opcionesString.size());
			
			return opcionesPrincial.get(opcionInt - 1);
		}
		
		public String ingresarNombreLinea()
		{
			return this.getInputString("Ingrese nombre para la linea:");
		}

		public int seleccionarTiposMaquina()
		{
			Collection<TipoMaquina> tipos = juego.getTiposMaquina();
			
			int index = 1;
			for(TipoMaquina tipo: tipos)
			{
				this.mensaje(String.valueOf(index) + ". " + tipo.getNombre());
				index++;
			}
			
			int opcion = this.getInputInt("Seleccione un tipo de maquina: ", 1, tipos.size()) - 1;
			
			return opcion;
		}

		public int seleccionarLineasProduccion()
		{
			List<LineaProduccion> lineas = juego.getJugador().getLineasProduccion();
			
			int index = 1;
			for(LineaProduccion linea: lineas)
			{
				this.mensaje(String.valueOf(index) + ". " + linea.getNombre());
				index++;
			}
			
			int opcion = this.getInputInt("Seleccione una linea de produccion: ", 1, lineas.size()) - 1;
			
			return opcion;
		}	
		
		public Point seleccionarPosicion() 
		{
			this.mensaje("Ingrese la posicion");
			Dimension dimension = juego.getJugador().getDimensionTerreno();
			int x = this.getInputInt(" - Coordenada en X:", 0, dimension.width);
			int y = this.getInputInt(" - Coordenada en Y:", 0, dimension.height);

			return new Point(x, y);
		}

		public int seleccionarTerreno() 
		{
			Collection<Terreno> terrenos = juego.getTerrenos();
			
			int index = 1;
			for(Terreno terreno: terrenos)
			{
				String descripcion = "Ancho: " + terreno.getAncho() + " - Alto: " + terreno.getAlto();
				descripcion += " - Compra: " + terreno.getPrecio(ModoAdquisicion.Compra);
				descripcion += " - Alquiler: " + terreno.getPrecio(ModoAdquisicion.Alquiler);

				this.mensaje(String.valueOf(index) + ". " + descripcion);
				index++;
			}
			
			int opcion = this.getInputInt("Seleccione un terreno: ", 1, terrenos.size()) - 1;
			
			return opcion;
		}

		public ModoAdquisicion seleccionarModoAdquisicionTerreno() 
		{
			ModoAdquisicion modo = null;
			
			this.mensaje("1. Compra");
			this.mensaje("2. Alquiler");
			
			int opcion = this.getInputInt("Seleccione un modo de adquisicion: ", 1, 2);
			
			if(opcion == 1) modo = ModoAdquisicion.Compra;
			if(opcion == 2) modo = ModoAdquisicion.Alquiler;
			
			return modo;
		}

		public Point seleccionarItem() 
		{
			Point posicion = null;
			
			while(posicion == null)
			{
				posicion = this.seleccionarPosicion();				
				
				if(!juego.getJugador().posicionTerrenoOcupada(posicion))
				{
					posicion = null;
				}				
			}

			return posicion;
		}
	}
	
	public class Control
	{		
		public void procesarOpcionPrincpal(OpcionPrincipal opcion)
		{
			switch(opcion)
			{
				case AdquirirTerreno:
					this.adquirirTerreno();
					break;
				case CrearLinea:
					try
					{
						juego.getJugador().crearLineaProduccion(menues.ingresarNombreLinea());
					}
					catch (Exception e) {}
					break;
				case ComprarMaquina:
					this.comprarMaquina();
					break;
				case ConectarMaquinas:
					this.conectarMaquinas();
					break;
				case CongelarTiempo:
					juego.congelarTiempo();
					break;
				case DescongelarTiempo:
					juego.descongelarTiempo();	
					break;
			}
		}
		
		private void conectarMaquinas()
		{
			Point origen = menues.seleccionarItem();
			Point destino = menues.seleccionarItem();
			
			try
			{
				juego.getJugador().conectarMaquinas(origen, destino);
			}
			catch (Exception e) 
			{
				menues.mensaje(e.getMessage());
			}
		}

		private void adquirirTerreno()
		{
			int indexTerreno = menues.seleccionarTerreno();
			ModoAdquisicion modo = menues.seleccionarModoAdquisicionTerreno();

			try
			{
				juego.getJugador().adquirirTerreno(indexTerreno, modo);
			}
			catch (Exception e) 
			{
				menues.mensaje(e.getMessage());
			}
		}

		public void comprarMaquina()
		{
			int indexTipoMaquina = menues.seleccionarTiposMaquina();
			int indexLinea = menues.seleccionarLineasProduccion();
			Point posicion = menues.seleccionarPosicion();
			
			try
			{
				juego.getJugador().comprarMaquina(indexTipoMaquina, posicion, indexLinea);
			}
			catch (Exception e) 
			{
				menues.mensaje(e.getMessage());
			}
		}
	}
}
